package com.navi.loaddata.loadService.impl.Dcdata;

import com.navi.loaddata.core.etlException.ETLException2;
import com.navi.loaddata.core.gpEntity.MArrayParamD;
import com.navi.loaddata.core.gpEntity.MParamD;
import com.navi.loaddata.core.mesEntity.MesCtPospairproduct;
import com.navi.loaddata.core.mesEntity.MesProducthistory;
import com.navi.loaddata.core.mesEntity.SpcDcResultData;
import com.navi.loaddata.core.mesEntity.SpcDcdata;
import com.navi.loaddata.core.mysqlEntity.EtlConfDModel;
import com.navi.loaddata.core.oracleEntity.*;
import com.navi.loaddata.core.oracleEntity.array.*;
import com.navi.loaddata.core.oracleEntity.base.EtlParamV;
import com.navi.loaddata.core.util.LoggerUtil;
import com.navi.loaddata.core.util.ProcessUtil;
import com.navi.loaddata.loadDao.SaveBaseDataDao;
import com.navi.loaddata.loadDao.SavePdsDataDao;
import com.navi.loaddata.loadService.impl.baseData.LoadBaseDataService;
import com.navi.loaddata.loadService.impl.baseData.LoadMesBaseDataService;
import com.navi.loaddata.loadService.impl.baseData.ProcessBaseDataService;
import org.apache.commons.collections.map.HashedMap;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.navi.loaddata.core.constant.GenericDef.*;
import static java.util.stream.Collectors.groupingBy;

/**
 * @author jay
 */
@Service
public class LoadDcDataService {
    private static final Logger logger = LoggerFactory.getLogger(LoadDcDataService.class);
    private LoggerUtil loggerUtil = new LoggerUtil(this.getClass());

    @Autowired
    private LoadMesBaseDataService loadMesBaseDataService;
    @Autowired
    private SaveBaseDataDao saveBaseDataDao;
    @Autowired
    private ProcessBaseDataService processBaseDataService;
    @Autowired
    private ProcessDcDataService processDcDataService;
    @Autowired
    private LoadDcInfoService loadDcInfoService;
    @Autowired
    private CheckDcDataService checkDcDataService;
    @Autowired
    private SavePdsDataDao savePdsDataDao;

    public String[] loadDcDataMain(EtlConfDModel etlConfD) throws Exception {
        String[] resMsg = loadDcData(etlConfD);
        String msg = etlConfD.getOpe();
        if (StringUtils.isEmpty(etlConfD.getOpe())) msg = "ALL";
        logger.info("OpeId={} loadDcDataMain finish!", msg);
        return resMsg;
    }

    /**
     * Load Dc Data
     *
     * @param etlConfD
     */
    private String[] loadDcData(EtlConfDModel etlConfD) throws Exception {
        String[] resMsg = new String[3];
        int okCnt = 0;
        int errCnt = 0;
        String errMsg = null;

        // DcData
        List<SpcDcdata> spcDcdataList = loadDcInfoService.loadDcDataList(etlConfD, "'" + DCTYPE_I + "','" + DCTYPE_P + "'");
        logger.info("Spc Dcdata count {}", spcDcdataList.size());
        if (!spcDcdataList.isEmpty()) {
            /**
             * etl_array_pds_result_v  & etl_array_pds_glass_summary_v
             *  1. PARAM_COLLECTION先固定，后续会从其PARAM表读取
             *  2. etl_array_pds_result_v 存row data （SITENAME可以转为数字的叫raw data, 如AVG/ASC就不包含在内）
             *  3. etl_array_pds_glass_summary_v 存汇总数据 （SITENAME 是字母的部分）
             * 		3.1 SITENAME = ASC => result 赋值给 PARAM_VALUE2, DATA_QTY 赋值 0
             * 		3.2 SITENAME = X   => result 赋值给 PARAM_VALUE, DATA_QTY 赋值 1
             * 			3.2.1 此时PARAM_VALUE,AVG,MAX, MIN 都填相同值（result）, RANGE  UI U2先空
             *      3.2 SITENAME  IN('AVG','MAX','MIN','SDV','RNG','U1','U2') => 赋值给对应的列
             * 	    3.3 DATA_QTY 记录 raw data的数量汇总
             * 		3.4 raw data >X > ASC
             * 	    3.5 PARAM_VALUE Default 资料顺位AVG-> X
             *  4. 根据主表数据的 Inspection 不同，分别查询 SPC_DCMEASUREDATARESULT & SPC_DCPROCESSDATARESULT
             *      4.1 Inspection => SPC_DCMEASUREDATARESULT
             *      4.2 Production => SPC_DCPROCESSDATARESULT
             * update
             * 	先固定处理 Inspection
             *
             */
            // base
            List<EtlStepV> etlStepVList = loadMesBaseDataService.loadAllFinalStep(etlConfD.getShop());
            List<EtlProductV> etlProductVList = loadMesBaseDataService.loadAllFinalProduct(etlConfD.getShop());
            // save base and proc
            saveBaseDataDao.saveBaseData(etlConfD, etlStepVList, etlProductVList);

            //param
            List<MParamD> ParamList = loadMesBaseDataService.loadParamInfo2(etlConfD.getShop());
            List<EtlParamV> etlParamList = processBaseDataService.processParamInfo2(ParamList);
            saveBaseDataDao.saveParamData(etlConfD, etlParamList);

            //cmn glass 只有ARRAY CF需要LOAD
            //cmn glass 可以批量入，  HST  资料也是
            if ("ARRAY".equals(etlConfD.getShop()) || "CF".equals(etlConfD.getShop())) {
                Map<String, MesCtPospairproduct> mapMesCt1 = processBaseDataService.getMapMesCt1();
//            Map<String, MesCtPospairproduct> mapMesCt2 =processBaseDataService.getMapMesCt2();

                //common glass 单片保存
                List<EtlCmnGlassV> etlCmnGlassVList = new ArrayList<>();
                Map<String, String> cmnGlass = new HashedMap();
                spcDcdataList.forEach(glass -> cmnGlass.put(glass.getMaterialname(), glass.getMaterialname()));
                for (String glassId : cmnGlass.keySet()) {
                    try {
                        List<MesProducthistory> commonGlassVList = loadMesBaseDataService.loadCommonGlassInfo(etlConfD, glassId);
                        EtlCmnGlassV etlCmnGlassV = processBaseDataService.processCmnGlass(etlConfD, commonGlassVList, mapMesCt1);
                        etlCmnGlassVList.add(etlCmnGlassV);
                    } catch (ETLException2 e) {
                        logger.error("glassId=" + glassId + " " + e.getErrorCode().getErrorMsg() + "错误原因：\n" + LoggerUtil.stackTraceToString(e));
                        if (StringUtils.isEmpty(errMsg)) {
                            errMsg = "glassId=" + glassId + " " + e.getErrorCode().getErrorMsg() + "错误原因：" + e.getErrMsg();
                        } else {
                            errMsg += "glassId=" + glassId + " " + e.getErrorCode().getErrorMsg() + "错误原因：" + e.getErrMsg();
                        }
                        errCnt++;
                        continue;
                    }
                }
                // save and procedure
                saveBaseDataDao.saveCmnGlass(etlConfD, etlCmnGlassVList);
                logger.info("CMN_GLASS保存成功！");
//                saveBaseDataDao.deleteCmnGlass(etlConfD);
            }


            saveBaseDataDao.deleteTeg2CmnAndParam(etlConfD);

            // DcData
            for (SpcDcdata spcDc : spcDcdataList) {
                //站点限制
                if (true == (ProcessUtil.opeLimit(spcDc.getProcessoperationname()))) {
                    logger.warn("glassId={} opeId={} 站点信息错误。忽略。", spcDc.getMaterialname(), spcDc.getProcessoperationname());
                    errCnt++;
                    continue;
                }
//                    //glassId长度限制
//                    if (spcDc.getMaterialname().length()) {
//                        logger.warn("glassId={} opeId={} 站点信息错误。忽略。",spcDc.getMaterialname(), spcDc.getProcessoperationname());
//                        errCnt++;
//                        continue;
//                    }
                try {
                    //getPDSresult
                    List<SpcDcResultData> spcDcResultDataList = new ArrayList<>();
                    if (DCTYPE_I.equals(spcDc.getDctype()))
                        spcDcResultDataList = loadDcInfoService.loadMDataList(etlConfD, spcDc.getDcdataid());
                    if (DCTYPE_P.equals(spcDc.getDctype()))
                        spcDcResultDataList = loadDcInfoService.loadPDataList(etlConfD, spcDc.getDcdataid());

                    if (spcDcResultDataList.isEmpty()) {
                        logger.warn("dcDataId=" + spcDc.getDcdataid() + " 对应的 spcDcResultDataList 为空，跳过。");
                        continue;
                    }

                    //process
                    EtlPdsGlassV etlPdsGlassV = processDcDataService.processDcData(etlConfD,spcDc);

                    List<EtlPdsResultV> etlPdsResultVList = new ArrayList<>();
                    List<EtlPdsGlassSummaryV> etlPdsGlassSummaryVList = new ArrayList<>();

                    String paramCollection = spcDc.getRecipename();
                    if (StringUtils.isEmpty(paramCollection)) {
                        paramCollection = spcDc.getProductspecname();
                        // 如果recipe为空，次笔数据不处理  改为赋值productId
                        logger.warn("DCDATAID={} recipe为空，", spcDc.getDcdataid());
//                    continue;
                    }


                    //同一dcdataId 批量处理他的result,summary
                    Map<String, List<SpcDcResultData>> mDataTree =
                            spcDcResultDataList.stream().collect(groupingBy(SpcDcResultData::getItemname));

                    for (Map.Entry<String, List<SpcDcResultData>> entry : mDataTree.entrySet()) {
                        EtlPdsGlassSummaryV etlPdsGlassSummaryV = new EtlPdsGlassSummaryV();
                        List<SpcDcResultData> curDcDataList = entry.getValue();


                        //赋值
                        // 数据检查
                        boolean[] resCheck=checkDcDataService.checkDcData(curDcDataList,spcDc);
                        boolean isCheck=resCheck[0];
                        boolean isRawData = resCheck[1];
                        boolean isXData = resCheck[2];
                        boolean isAscData = resCheck[3];

                        if(!isCheck) continue;


                        int resultListCnt = curDcDataList.size();
                        SpcDcResultData firstResult = curDcDataList.get(0);

                        // 赋值
                        etlPdsGlassSummaryV = processDcDataService.processPdsGlassSummary(etlPdsGlassV, paramCollection, firstResult);
                        for (int j = 0; j < resultListCnt; j++) {
                            SpcDcResultData curResult = curDcDataList.get(j);
                            String curSiteName = curResult.getSitename();
                            Double resVal = ProcessUtil.getDouble(curResult.getResult());
                            if (isRawData) {
                                if (ProcessUtil.isNumeric(curSiteName)) {
                                    // 数字类型 raw data
                                    EtlPdsResultV result = processDcDataService.processPdsResultData(etlConfD,spcDc,paramCollection,curResult);
                                    etlPdsResultVList.add(result);
                                } else if (SUM_SITE_LIST.contains(curSiteName)) {
                                    // 预定义的SUM类型
                                    if (SITE_AVG.equals(curSiteName)) {
                                        etlPdsGlassSummaryV.setAvg(resVal);
                                    } else if (SITE_MAX.equals(curSiteName)) {
                                        etlPdsGlassSummaryV.setMax(resVal);
                                    } else if (SITE_MIN.equals(curSiteName)) {
                                        etlPdsGlassSummaryV.setMin(resVal);
                                    } else if (SITE_SDV.equals(curSiteName)) {
                                        etlPdsGlassSummaryV.setStd(resVal);
                                        etlPdsGlassSummaryV.setThreeSigma(resVal * 3);
                                    } else if (SITE_RNG.equals(curSiteName)) {
                                        etlPdsGlassSummaryV.setRange(resVal);
                                    } else if (SITE_U1.equals(curSiteName)) {
                                        etlPdsGlassSummaryV.setUniformity1(resVal);
                                    } else if (SITE_U2.equals(curSiteName)) {
                                        etlPdsGlassSummaryV.setUniformity2(resVal);
                                    }
                                } else {
                                    logger.error("Raw data 包含无效的字符串，DCDATAID: {}， Site name {}", spcDc.getDcdataid(), curSiteName);
                                }
                            } else if (isXData) {
                                etlPdsGlassSummaryV.setParamValue(resVal);
                                etlPdsGlassSummaryV.setMax(resVal);
                                etlPdsGlassSummaryV.setMin(resVal);
                                etlPdsGlassSummaryV.setAvg(resVal);
                                etlPdsGlassSummaryV.setDataQty(1.0);
                            } else if (isAscData) {
                                etlPdsGlassSummaryV.setParamValue2(curResult.getResult());
                                etlPdsGlassSummaryV.setDataQty(0.0);
                            }
                        }
                        if (isRawData) {
                            etlPdsGlassSummaryV.setDataQty((double) etlPdsResultVList.size());
                            etlPdsGlassSummaryV.setParamValue(etlPdsGlassSummaryV.getAvg());
                        }
                        etlPdsGlassSummaryVList.add(etlPdsGlassSummaryV);

                    }// End of for Map

                    // save
                    savePdsDataDao.savePdsData(etlConfD, etlPdsGlassV, etlPdsGlassSummaryVList, etlPdsResultVList);
                    savePdsDataDao.deletePds(etlConfD);

                } catch (ETLException2 e) {
                    logger.error("dcDataId=" + spcDc.getDcdataid() + " " + e.getErrorCode().getErrorMsg() + "错误原因：\n" + LoggerUtil.stackTraceToString(e));
                    if (StringUtils.isEmpty(errMsg)) {
                        errMsg = "dcDataId=" + spcDc.getDcdataid() + " " + e.getErrorCode().getErrorMsg() + "错误原因：" + e.getErrMsg();
                    } else {
                        errMsg += "dcDataId=" + spcDc.getDcdataid() + " " + e.getErrorCode().getErrorMsg() + "错误原因：" + e.getErrMsg();
                    }
                    errCnt++;
                    continue;
                }

            }// end of for curDCList


        } else {
            logger.info("没有此区间的数据。"); // todo print log & save etl data
        }
        return resMsg;
    }

}
